<?php
/**
 * Created by PhpStorm.
 * User: lenovo
 * Date: 2020/9/16
 * Time: 19:47
 */

namespace App\Services;


use App\Logic\UserGroupLogic;
use App\Model\FriendModel;
use App\Model\GroupModel;
use App\Model\MsgModel;
use App\Model\UserGroupModel;
use App\Model\UserModel;
use EasySwoole\Component\TableManager;
use EasySwoole\RedisPool\RedisPool;
use EasySwoole\EasySwoole\Config;
use EasySwoole\EasySwoole\ServerManager;
use App\Logic\ToolLogic;

class MsgService
{
    /**私聊业务
     * @param array $param
     */
    function  priveteChat( Array $param,$userInfo,$offline=false){
        #消息去重
        try{
            $messageInfo = MsgModel::create()->get(['user_id'=>$userInfo['id'],'nonce'=>$param['nonce']]);
            if(!empty($messageInfo)){
                $messageArr = array(
                    'code'=>ReponseCodeService::CODE_OK,
                    'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_OK],
                    'data'=>json_encode(array(),JSON_FORCE_OBJECT),
                    'action'=>'chat',
                    'nonce'=>$param['nonce'],
                    'time'=>HelpService::msectime(),
                    'user_id'=>$userInfo['id'],
                    'msg_id'=>$messageInfo['id'],
                );
                return  $messageArr;
            }
        }catch(\Throwable $t){
            echo $t->getMessage();
            $messageArr = array(
                'code'=>ReponseCodeService::CODE_SERVICE_UNAVAILABLE,
                'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_SERVICE_UNAVAILABLE],
                'data'=>json_encode(array(),JSON_FORCE_OBJECT),
                'action'=>'chat',
                'nonce'=>$param['nonce'],
                'time'=>HelpService::msectime(),
                'user_id'=>$userInfo['id'],
                'msg_id'=>'',
            );
            return  $messageArr;
        }


        $host = Config::getInstance()->getConf('APP.FILE_DOMAIN');
        $param['content'] = trim($param['content'],'/');
        switch ($param['type']){
            case PrivateMsgService::MSG_TYPE_IMAGE://图片,后续等比缩放
                $param['extra']['url'] = "{$host}{$param['content']}";
                $thumbWidth = 480;
                $thumbHeight = (int)($thumbWidth/$param['extra']['width']*$param['extra']['height']);
                $param['extra']['thumb_url'] = ToolLogic::thumb($param['content'],$thumbWidth,$thumbHeight);

                $param['extra']['thumbHeight'] = $thumbHeight;
                $param['extra']['thumbWidth'] = $thumbWidth;
                break;
            case PrivateMsgService::MSG_TYPE_VOICE:
                $param['extra']['voice_url'] = "{$host}{$param['content']}";
                break;
            case PrivateMsgService::MSG_TYPE_VIDEO://视频,后续等比缩放
                $thumbWidth = 480;
                $thumbHeight = 360;
                $param['extra']['cover_url'] = ToolLogic::videoCover($param['content'],$thumbWidth,$thumbHeight);
                $param['extra']['thumbHeight'] = $thumbHeight;
                $param['extra']['thumbWidth'] = $thumbWidth;
                $param['extra']['video_url'] = "{$host}{$param['content']}";
                break;
            case PrivateMsgService::MSG_TYPE_FILE://文件
                $param['extra']['download_url'] = $host.trim($param['content'],'/');
                $param['extra']['file_image'] = 'https://hbimg.huabanimg.com/9520b252c184eb0e9ea3e63c8b0167a45481e7ce17317-i5F6He_fw658/format/webp';
            #自动换文件大小单位
        }
        $data = array(
            'to_user_id' =>$param['to_user_id'],
            'app_user_id'=>$userInfo['app_user_id'],
            'to_app_user_id'=>$param['to_app_user_id'],
            'user_id'=>$userInfo['id'],
            'content'=>$param['content'],
            'nickname'=>$userInfo['nickname'],
            'head'=>$userInfo['head'],
            'type'=>$param['type'],
            'extra'=>$param['extra']
        );

        //消息入库
        $friendService = new FriendService();
        $getUnionInfo = $friendService->getUnionInfo($userInfo['id'],$param['to_user_id']);
        if( !is_object($getUnionInfo)){

            $messageArr = array(
                'data'=>json_encode(array(),JSON_FORCE_OBJECT),
                'action'=>'chat',
                'nonce'=>$param['nonce'],
                'time'=>HelpService::msectime(),
                'user_id'=>$userInfo['id'],
                'msg_id'=>$messageInfo['id'],
            );
            $messageArr['code'] = ReponseCodeService::CODE_USER_NOT_FUND;
            $messageArr['msg'] = ReponseCodeService::$phrases[ReponseCodeService::CODE_USER_NOT_FUND];
            return $messageArr;
        }

        if($offline==true){
            $msgId  = $param['msg_id'];
        }else{
            if($param['type']!=PrivateMsgService::MSG_TYPE_MSG_REPONSE){
                #创建
                $insertData['sub_type'] = MsgModel::SUB_TYPE_PRY_MSG;
                $insertData['app_id'] = $userInfo['app_id'];
                $insertData['user_id'] = $userInfo['id'];
                $insertData['to_id'] = $param['to_user_id'];
                $insertData['type'] = $param['type'];
                $insertData['unionid'] = $getUnionInfo['unionid'];
                $insertData['msg'] = $param['content'];
                $insertData['nonce'] =  $param['nonce'];
                $insertData['extra'] = json_encode(    $param['extra']);
                $insertData['created_at'] = HelpService::msectimeToStr(HelpService::msectime());
                $insertData['updated_at'] = HelpService::msectimeToStr(HelpService::msectime());

                //消息去重
                $msgId = MsgModel::create()->where(['user_id'=>$userInfo['id'],'nonce'=>$param['nonce']])->column('id');
                if(!$msgId){
                    $msgId = MsgModel::create()->data( $insertData)->save();
                }

            }else{
                $msgId = $param['msg_id'];
                #消息已阅读
                MsgModel::create()->update(['status'=>MsgModel::STATUS_READ],['id'=> $msgId]);
                #给对方发消息
            }
        }
        $messageArr = array(
            'code'=>ReponseCodeService::CODE_OK,
            'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_OK],
            'data'=>json_encode($data,JSON_FORCE_OBJECT),
            'action'=>'chat',
            'nonce'=>$param['nonce'],
            'time'=>HelpService::msectime(),
            'user_id'=>$userInfo['id'],
            'msg_id'=> $msgId,
        );

        #黑名单校验
        $blackListService = new BlackListService();
        if($blackListService->isBlackList($param['to_user_id'],$userInfo['id'])){
            $messageArr['code'] = ReponseCodeService::CODE_BLACK_LIST;
            $messageArr['msg'] = '发送失败';
            return $messageArr;
        }

        $this->pushMessage($param['to_user_id'],$messageArr, $msgId);
        return  $messageArr;
    }


    /**获取私聊历史消息
     * @param $param
     * @param $userInfo
     */
    public function privateList($param, $userInfo){
        $host = Config::getInstance()->getConf('APP.FILE_DOMAIN');
        try{
            $count = isset($param['extra']['count'])?$param['extra']['count']:20;
            $app_user_id = $param['extra']['app_user_id'];
            $appId =  $userInfo['app_id'];

            $friendUserInfo = UserModel::create()->get(['app_user_id'=>$app_user_id,'app_id'=>$appId]);
            if(empty(  $friendUserInfo )){
                return ReponseCodeService::CODE_BAD_REQUEST;
            }
            $friendInfo = FriendModel::create()->get(['user_id'=>$userInfo['id'],'friend_user_id'=>$friendUserInfo['id']]);
            if(empty( $friendInfo)){
                return ReponseCodeService::CODE_BAD_REQUEST;
            }
            $list  = array();
            if(isset($param['extra']['msg_id'])&&!empty($param['extra']['msg_id'])){
                $lastMeaasge = MsgModel::create()->get(['id'=>$param['extra']['msg_id']]);
                if(!empty($lastMeaasge)){
                    $model = MsgModel::create()->where(['unionid'=>$friendInfo['unionid'],'app_id'=>$appId,'id'=>[$lastMeaasge['id'],'<'],'status'=>MsgModel::STATUS_NON_DELIVERY])->limit(0, $count )->order('created_at')->withTotalCount();
                    $list = $model->all(null);
                }
            }else{
                $model = MsgModel::create()
                    ->where(['unionid'=>$friendInfo['unionid'],'app_id'=>$appId,'status'=>MsgModel::STATUS_NON_DELIVERY])->limit(0, $count)
                    ->order('created_at')
                    ->withTotalCount();
                $list = $model->all(null);
            }

            $retList = array();
            if(!empty( $list)){
                foreach ( $list as $meaasge){
                    #发信人
                    $userInfo = UserModel::create()->get(['id'=>$meaasge['user_id']]);
                    #接收人
                    $receiverInfo = UserModel::create()->get(['id'=>$meaasge['to_id']]);
                    $data = array(
                        'user_id' =>$userInfo['id'],
                        'content'=>$meaasge['msg'],
                        'type'=>$meaasge['type'],
                        'extra'=>json_decode($meaasge['extra'],true),
                        'app_user_id'=>$userInfo['app_user_id'],
                        'nickname'=>$userInfo['nickname'],
                        'head'=>$userInfo['head'],
                        'to_app_user_id'=> $receiverInfo['app_user_id']
                    );

                    #文件处理
                    switch ($data['type']){
                        case MsgModel::MSG_TYPE_IMAGE://图片,后续等比缩放
                            $data['extra']['url'] = "{$host}{$data['content']}";
                            $thumbWidth = 480;
                            $thumbHeight = (int)($thumbWidth/$data['extra']['width']* $data['extra']['height']);
                            $data['extra']['thumb_url'] = "{$host}{$data['content']}?/3/w/{$thumbWidth}/h/{$thumbHeight}";

                            $data['extra']['thumbHeight'] = $thumbHeight;
                            $data['extra']['thumbWidth'] = $thumbWidth;
                            break;
                        case MsgModel::MSG_TYPE_VOICE:
                            $data['extra']['voice_url'] = "{$host}{$data['content']}";
                            break;
                        case MsgModel::MSG_TYPE_VIDEO://视频,后续等比缩放
                            $thumbWidth = 480;
                            $thumbHeight = 360;
                            $data['extra']['cover_url'] = "{$host}{$data['content']}?vframe/jpg/offset/0/w/{$thumbWidth}/h/{$thumbHeight}";
                            $data['extra']['thumbHeight'] = $thumbHeight;
                            $data['extra']['thumbWidth'] = $thumbWidth;
                            $data['extra']['video_url'] = "{$host}{$data['content']}";
                            break;
                        default:

                    }
                    $messageArr = array(
                        'data'=>json_encode($data),
                        'action'=>'chat',
                        'nonce'=>$meaasge['nonce'],
                        'time'=> HelpService::strDateToMsectime($meaasge['created_at']),
                        'msg_id'=>$meaasge['msg_id'],
                        'user_id' =>$userInfo['id'],
                        'app_user_id'=>$userInfo['app_user_id'],
                        'nickname'=>$userInfo['nickname'],
                        'head'=>$userInfo['head'],
                    );
                    $retList[] = $messageArr;
                }
                //  sort($retList);
            }
        }catch(\Throwable $t){
            echo $t->getMessage();
            return ReponseCodeService::CODE_SERVICE_UNAVAILABLE;
        }
        return  $retList;
    }


    /**获取群消息，群聊历史消息
     * @param $groupId
     * @param $startMessage
     */
    public function groupList($param, $userInfo){
        $host = Config::getInstance()->getConf('APP.FILE_DOMAIN');
        try{
            $count = isset($param['extra']['count'])?$param['extra']['count']:20;
            $group_id = $param['extra']['group_id'];
            $appId =  $userInfo['app_id'];
            $userGroup = UserGroupModel::create()->get(['user_id'=>$userInfo['id'],'group_id'=>$group_id,'status'=>UserGroupModel::STATUS_NORMAL]);
            if(empty($userGroup)){
                return ReponseCodeService::CODE_NOT_GROUP_MEMBER;
            }
            $delMsg = '';
            if(!empty($userGroup['last_msg_id'])){
                $delMsg = MsgModel::create()->get(['id'=>$userGroup['last_msg_id']]);
            }

            if(isset($param['extra']['msg_id'])&&!empty($param['extra']['msg_id'])){
                $lastMeaasge = MsgModel::create()->get(['id'=>$param['extra']['msg_id']]);
                $list = array();
                if(!empty($lastMeaasge)){
                    $msgWhere = ['to_id'=>$group_id,
                        'app_id'=>$appId,
                        'id'=>[$lastMeaasge['id'],'>'],
                        'sub_type'=>MsgModel::SUB_TYPE_GOUP_MSG
                    ];
                    if(!empty($delMsg)){
                        $msgWhere = "to_id={$group_id} and app_id={$appId} and sub_type=".MsgModel::SUB_TYPE_GOUP_MSG." and id>{$lastMeaasge['id']} and id>{$delMsg['id']}";
                    }
                    $model = MsgModel::create()->where($msgWhere)->limit(0, $count )->order('created_at')->withTotalCount();
                    $list = $model->all(null);
                }
            }else{
                $msgWhere = ['to_id'=>$group_id,'app_id'=>$appId];
                if(!empty($delMsg)){
                    $msgWhere = "to_id={$group_id} and app_id={$appId} and id>{$delMsg['id']} and sub_type=".MsgModel::SUB_TYPE_GOUP_MSG;
                }
                $model = MsgModel::create()
                    ->where( $msgWhere )->limit(0, $count)
                    ->order('created_at')
                    ->withTotalCount();
                $list = $model->all(null);
            }

            $groupInfo = GroupModel::create()->get(['id'=>$group_id]);

            $retList = array();
            if(!empty( $list)){
                foreach ( $list as $meaasge){
                    $userInfo = UserModel::create()->get(['id'=>$meaasge['user_id']]);
                    if(empty($userInfo)){
                        continue;
                    }
                    $data = array(
                        'group_id' =>$group_id,
                        'content'=>$meaasge['msg'],
                        'type'=>$meaasge['type'],
                        'extra'=>json_decode($meaasge['extra'],true),
                        'app_user_id'=>$userInfo['app_user_id'],
                        'nickname'=>$userInfo['nickname'],
                        'head'=>$userInfo['head'],
                    );

                    #文件处理
                    switch ($data['type']){
                        case PrivateMsgService::MSG_TYPE_IMAGE://图片,后续等比缩放
                            $data['extra']['url'] = "{$host}{$data['content']}";
                            $thumbWidth = 480;
                            $thumbHeight = (int)($thumbWidth/ $data['extra']['width']* $data['extra']['height']);
                            $data['extra']['thumb_url'] = "{$host}{$data['content']}?/3/w/{$thumbWidth}/h/{$thumbHeight}";

                            $data['extra']['thumbHeight'] = $thumbHeight;
                            $data['extra']['thumbWidth'] = $thumbWidth;
                            break;
                        case PrivateMsgService::MSG_TYPE_VOICE:
                            $data['extra']['voice_url'] = "{$host}{$data['content']}";
                            break;
                        case PrivateMsgService::MSG_TYPE_VIDEO://视频,后续等比缩放
                            $thumbWidth = 480;
                            $thumbHeight = 360;
                            $data['extra']['cover_url'] = "{$host}{$data['content']}?vframe/jpg/offset/0/w/{$thumbWidth}/h/{$thumbHeight}";
                            $data['extra']['thumbHeight'] = $thumbHeight;
                            $data['extra']['thumbWidth'] = $thumbWidth;
                            $data['extra']['video_url'] = "{$host}{$data['content']}";
                            break;
                    }
                    $data['service_msg'] = false;
                    if($groupInfo['service_user_id']!=0){
                        $data['service_msg'] = true;
                    }
                    $messageArr = array(
                        'data'=>json_encode($data),
                        'action'=>'groupChat',
                        'nonce'=>$meaasge['nonce'],
                        'time'=> HelpService::strDateToMsectime($meaasge['created_at']),
                        'msg_id'=>$meaasge['msg_id'],
                        'group_id' =>$group_id,
                    );
                    $retList[] = $messageArr;
                }
                sort($retList);
            }
        }catch(\Throwable $t){
            return ReponseCodeService::CODE_SERVICE_UNAVAILABLE;
        }

        return  $retList;
    }


    /**群聊业务
     * @param array $param
     * @param $userInfo
     * @param bool $offline
     */
    public function groupChat( Array $param,$userInfo){
        $param['extra'] = isset($param['extra'])?$param['extra']:array();
        ltrim($param['content'],'/');
        $host = Config::getInstance()->getConf('APP.FILE_DOMAIN');
        switch ($param['type']){
            case MsgModel::MSG_TYPE_IMAGE://图片,后续等比缩放
                $param['extra']['url'] = "{$host}{$param['content']}";
                $thumbWidth = 480;
                $thumbHeight = (int)($thumbWidth/$param['extra']['width']*$param['extra']['height']);
                $param['extra']['thumb_url'] = ToolLogic::thumb($param['content'],$thumbWidth,$thumbHeight);
                $param['extra']['thumbHeight'] = $thumbHeight;
                $param['extra']['thumbWidth'] = $thumbWidth;
                break;
            case MsgModel::MSG_TYPE_VOICE:
                $param['extra']['voice_url'] = "{$host}{$param['content']}";
                break;
            case MsgModel::MSG_TYPE_VIDEO:
                $thumbWidth = 480;
                $thumbHeight = 360;
                $param['extra']['cover_url'] = ToolLogic::videoCover($param['content'],$thumbWidth,$thumbHeight);;
                $param['extra']['thumbHeight'] = $thumbHeight;
                $param['extra']['thumbWidth'] = $thumbWidth;
                $param['extra']['video_url'] = "{$host}{$param['content']}";
                break;
            case MsgModel::MSG_TYPE_FILE://文件
                $param['extra']['download_url'] = $host.$param['content'];
                $param['extra']['file_image'] = 'https://hbimg.huabanimg.com/9520b252c184eb0e9ea3e63c8b0167a45481e7ce17317-i5F6He_fw658/format/webp';
        }

        $groupInfo = GroupModel::create()->get(['id'=>$param['group_id']]);

        $data = array(
            'group_id' =>$param['group_id'],
            'content'=>$param['content'],
            'type'=>$param['type'],
            'extra'=>$param['extra'],
            'app_user_id'=>$userInfo['app_user_id'],
            'nickname'=>$userInfo['nickname'],
            'head'=>$userInfo['head'],
        );

        if(empty($groupInfo)){
            $messageArr = array(
                'code'=>ReponseCodeService::CODE_GROUP_NOT_FUND ,
                'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_GROUP_NOT_FUND],
                'data'=>json_encode($data),
                'action'=>'groupChat',
                'nonce'=>$param['nonce'],
                'time'=>HelpService::msectime(),
                'msg_id'=>null,
                'group_id' =>$param['group_id'],
            );
            return $messageArr;
        }

        $data['service_msg'] = false;
        if($groupInfo['service_user_id']!=0){
            $data['service_msg'] = true;
        }
        $msgId = null;
        #校验群是否正常
        if($groupInfo['status']!=GroupModel::STATUS_NORMAL){
            $messageArr = array(
                'code'=>ReponseCodeService::CODE_GROUP_NOT_FUND,
                'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_GROUP_NOT_FUND],
                'data'=>json_encode($data),
                'action'=>'groupChat',
                'nonce'=>$param['nonce'],
                'time'=>HelpService::msectime(),
                'msg_id'=>$msgId,
                'group_id' =>$param['group_id'],
            );
            return $messageArr;
        }
        #校验是否本群成员
        $userGroupWhere['group_id'] = $param['group_id'];
        $userGroupWhere['user_id'] = $userInfo['id'];
        $userGroupWhere['status'] = UserGroupModel::STATUS_NORMAL;
        if(!UserGroupModel::create()->get($userGroupWhere)){
            $messageArr = array(
                'code'=>ReponseCodeService::CODE_NOT_GROUP_MEMBER ,
                'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_NOT_GROUP_MEMBER],
                'data'=>json_encode($data),
                'action'=>'groupChat',
                'nonce'=>$param['nonce'],
                'time'=>HelpService::msectime(),
                'msg_id'=>$msgId,
                'group_id' =>$param['group_id'],
            );
            return $messageArr;
        }
        //消息入库
        $insertData['to_id'] = $param['group_id'];
        $insertData['sub_type'] = MsgModel::SUB_TYPE_GOUP_MSG;
        $insertData['nonce'] = $param['nonce'];
        $insertData['user_id'] = $userInfo['id'];
        $insertData['msg'] = $param['content'];
        $insertData['app_id'] = $userInfo['app_id'];
        $insertData['extra'] = json_encode($param['extra']);
        $insertData['type'] = $param['type'];
        $insertData['created_at'] = HelpService::msectimeToStr(HelpService::msectime());
        $insertData['updated_at'] = HelpService::msectimeToStr(HelpService::msectime());
        try{
            if($insertData['type']!=MsgModel::MSG_TYPE_MSG_REPONSE){
              $msgId =   MsgModel::create()->data( $insertData)->save();
            }
        }catch(\Throwable $t){
            echo $t->getMessage();
            return false;
        }

        $messageArr = array(
            'code'=>ReponseCodeService::CODE_OK,
            'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_OK],
            'data'=>json_encode($data),
            'action'=>'groupChat',
            'nonce'=>$param['nonce'],
            'time'=>HelpService::msectime(),
            'msg_id'=>$msgId,
            'group_id' =>$param['group_id'],
        );

        //发布订阅
        $redisPool = \EasySwoole\RedisPool\Redis::getInstance()->get('redis');
        $redis = $redisPool->getObj();
        $redis->publish(Config::getInstance()->getConf('CHAT.group_chat'),json_encode($messageArr));
        $redisPool->recycleObj($redis);
        return $messageArr;
    }


    /**
     * 同步推送连接服务到登录成功这段时间的离线消息
     */
    public function offLineMessage($userId){
        try{
            $userInfo = UserModel::create()->get(['id'=>$userId]);
            #同步个人消息

            #同步群聊消息
            go(function () use($userId){
                $this->syncGroupMsg($userId);
            });
            #同步群\个人系统消息
            $systemMessageService = new SystemMessageService();
            $systemMessageService->syncSystemMsg($userInfo);

     }catch(\Throwable $t){
            echo $userId.'同步离线消息失败：'.$t->getMessage().PHP_EOL;
        }

    }

    /**
     * 同步单聊离线
     */
    public function syncPriveteChat($userId){
        try{
            #补推送登录到正常状态的系统消息
            $redisPool = \EasySwoole\RedisPool\Redis::getInstance()->get('redis');
            $redis = $redisPool->getObj();
            if(!empty($redis)){
                $userService = new UserService();
                $toUserInfo = $userService->getUserOnlineInfo($userId);
                if(empty($toUserInfo)){
                    return false;
                }
                $startTime = HelpService::msectimeToStr($toUserInfo['login_time']);
            }else{
                $startTime = '';
            }

            if(!empty($startTime)){
                $where['created_at'] = [$startTime,'>'];
            }
            $where['to_id'] = $userId;
            $where['sub_type'] = MsgModel::SUB_TYPE_PRY_MSG;
            $where['status']  = MsgModel::STATUS_NON_DELIVERY;
            $page = 1;          // 当前页码
            $limit = 100;        // 每页多少条数据
            $model =MsgModel::create()->limit($limit * ($page - 1), $limit)->withTotalCount();
            $list = $model->all($where);
            $result = $model->lastQueryResult();
            $total = $result->getTotalCount();
            $totalPage = ceil($total/$limit);
            $pushMessageService = new PushMessageService();

            if(!empty($list)){
                echo '非空'.PHP_EOL;
                while ($page<=$totalPage){
                    foreach ($list as $message){
                        $msgId = $message['id'];
                        echo    '个人消息id:'.$msgId.PHP_EOL;
                        $data = array(
                            'user_id' => $message['to_id'],
                            'content'=>$message['content'],
                            'type'=>$message['type'],
                            'extra'=>json_decode($message['extra']),
                        );
                        $messageArr = array(
                            'code'=>ReponseCodeService::CODE_OK,
                            'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_OK],
                            'data'=>json_encode($data),
                            'action'=>'chat',
                            'nonce'=>$message['nonce'],
                            'time'=>HelpService::msectime(),
                            'msg_id'=>$msgId,
                            'user_id'=>$message['to_id']
                        );
                        $pushMessageService->push($toUserInfo['fd'],$messageArr);
                        #修改消息状态
                        MsgModel::create()->update(['status'=>MsgModel::STATUS_DELIVERED],['id'=>$message['id']]);
                    }
                    $page = $page+1;
                    $model =MsgModel::create()->limit($limit * ($page - 1), $limit)->withTotalCount();
                    $list = $model->all($where);
                }
            }
            return  true;
        }catch(\Throwable $t){
            return ReponseCodeService::CODE_SERVICE_UNAVAILABLE;
        }
    }

    /**
     * 同步群聊消息
     */
    public function syncGroupMsg($userId){
        try{
            $userGroupWhere = array(
                'user_id'=>$userId,
                'status' => UserGroupModel::STATUS_NORMAL
            );

            $userGroupArr = UserGroupModel::create()->where($userGroupWhere )->column('group_id');
            #没有需要同步的，直接认为成功
            if(empty($userGroupArr)){
                echo '没有群消息要同步'.PHP_EOL;
                return true;
            }
            echo '一共'.count($userGroupArr).'个群'.PHP_EOL;

            $where  = array(
                'to_id'=>[$userGroupArr,'in']
            );

            #补推送登录到正常状态的系统消息
            $redisPool = \EasySwoole\RedisPool\Redis::getInstance()->get('redis');
            $redis = $redisPool->getObj();
            if(!empty($redis)){
                $userService = new UserService();
                $toUserInfo = $userService->getUserOnlineInfo($userId);
                if(empty($toUserInfo)){
                    return false;
                }
                $startTime = HelpService::msectimeToStr($toUserInfo['login_time']);
            }else{
                $startTime = '';
            }

            if(!empty($startTime)){
                $where['created_at'] = [$startTime,'>'];
            }
            $where['sub_type'] = MsgModel::SUB_TYPE_GOUP_MSG;
            $page = 1;          // 当前页码
            $limit = 100;        // 每页多少条数据
            $model =MsgModel::create()->limit($limit * ($page - 1), $limit)->withTotalCount();
            $list = $model->all($where);
            $result = $model->lastQueryResult();
            $total = $result->getTotalCount();
            $totalPage = ceil($total/$limit);
            $pushMessageService = new PushMessageService();

            if(!empty($list)){
                echo '非空'.PHP_EOL;
                while ($page<=$totalPage){
                    foreach ($list as $message){
                        $msgId = $message['id'];
                        echo    '群消息id:'.$msgId.PHP_EOL;
                        $data = array(
                            'group_id' => $message['to_id'],
                            'content'=>$message['content'],
                            'type'=>$message['type'],
                            'extra'=>json_decode($message['extra']),
                            'sub_type'=>MsgModel::MSG_SUB_TYPE_GROUP,
                        );

                        $messageArr = array(
                            'code'=>ReponseCodeService::CODE_OK,
                            'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_OK],
                            'data'=>json_encode($data),
                            'action'=>'systemMessage',
                            'nonce'=>$message['nonce'],
                            'time'=>HelpService::msectime(),
                            'msg_id'=>$msgId,
                            'group_id'=>$message['to_id']
                        );
                        $pushMessageService->push($toUserInfo['fd'],$messageArr);
                    }
                    $page = $page+1;
                    $model =MsgModel::create()->limit($limit * ($page - 1), $limit)->withTotalCount();
                    $list = $model->all($where);
                }
            }
            return  true;
        }catch(\Throwable $t){
            return ReponseCodeService::CODE_SERVICE_UNAVAILABLE;
        }
    }



    /**推送消息给客户端
     * @param $toUserId
     * @param $messageArr
     * @return bool
     */
    public function pushMessage($toUserId,$messageArr,$messageId=0){
        $userService = new UserService();
        $toUserInfo = $userService->getUserOnlineInfo($toUserId);
        if(empty($toUserInfo)){
            return false;
        }
        #校验用户是否就绪
        $readyTable =  TableManager::getInstance()->get(Config::getInstance()->getConf('CHAT.user_ready'));
        $readyInfo = $readyTable->get($messageArr['user_id']);
        if(empty($readyInfo)){
            return false;
        }

        if($toUserInfo['server'] == Config::getInstance()->getConf('APP.CURRENT.host')){
            echo '本机';
            $server = ServerManager::getInstance()->getSwooleServer();
            $info = $server->getClientInfo($toUserInfo['fd']);
            /** 判断此fd 是否是一个有效的 websocket 连接 */
            if($info && $info['websocket_status'] == WEBSOCKET_STATUS_FRAME) {
                //本机推送
                $encodeMsg = HelpService::aesEncrypt(json_encode($messageArr),$toUserInfo['access_key'], $toUserInfo['secret_key']);
                if($server->push($toUserInfo['fd'],  $encodeMsg)){
                    if($messageId==0){
                        return true;
                    }
                    //修改消息状态
                    try{
                        MsgModel::create()->update([
                            'status' => MsgModel::STATUS_DELIVERED,
                        ], ['id' => $messageId]);
                    }catch(\Throwable $t){
                        return false;
                    }
                    return true;
                }else{//推送失败，更新用户在线信息，走离线消息
                    go(function ()use($toUserId){
                        $userService = new UserService();
                        $userService->updateLocalUserOnlineInfo($toUserId);
                    });
                    return false;
                }
            }

            return false;
        }

        //跨机器
        echo "跨机器推送，{$toUserInfo['server']}".PHP_EOL;
        #跨机消息推送，接收方去更新消息状态，发送方不管
        return $this->pushToOtherServer($toUserInfo['server'],$toUserInfo['fd'],json_encode($messageArr));
    }

    /**
     * 最近联系信息
     */
    public function recentChat($param,$userInfo){
        try{
            $host = Config::getInstance()->getConf('APP.FILE_DOMAIN');
            #最近的联系人
            $friendCondition = array(
                'friends.user_id'=>$userInfo['id']
            );
            echo '获取好友信息';
            $friendList = FriendModel::create()
                ->join('users','friends.friend_user_id=users.id')
                ->field('users.id,users.app_user_id,users.nickname,users.head,unionid')
                ->all($friendCondition);
            $friends = array();
            #计算私人联系人的消息数量
            if(!empty($friendList)){
                foreach ($friendList as $k=>$f){
                    $count = MsgModel::create()->where(['to_id'=>$userInfo['id'],'user_id'=>$f['id'],'status'=>MsgModel::STATUS_NON_DELIVERY,'sub_type'=>MsgModel::SUB_TYPE_PRY_MSG])->count();
                    if($count<=0){
                        echo '没有离线消息';
                        continue;
                    }
                    echo '有好友消息'.PHP_EOL;
                    #干掉未接收数据数量
                    MsgModel::create()->update(['status'=>MsgModel::STATUS_DELIVERED],['to_id'=>$userInfo['id'],'user_id'=>$f['id'],'status'=>MsgModel::STATUS_NON_DELIVERY,'sub_type'=>MsgModel::SUB_TYPE_PRY_MSG]);
                    #$lastMsg = MsgModel::create()->order('id')->get(['unionid'=>$f['unionid']]);
                    $list = MsgModel::create()->order('id','desc')->limit(10)->all(['unionid'=>$f['unionid']]);
                    foreach ( $list as $msg){
                        #发信人是对方
                        if($msg['to_id']==$userInfo['id']){
                            $receiverInfo = $userInfo;
                            $senderInfo = $f;
                        }else{
                            $receiverInfo = $f;
                            $senderInfo = $userInfo;
                        }
                        $friend['app_user_id'] =  $senderInfo['app_user_id'];
                        $friend['count'] = $count;
                        $friend['nickname'] = $senderInfo['nickname'];
                        $friend['head'] = $senderInfo['head'];
                        $data = array(
                            'to_user_id' =>$msg['to_id'],
                            'app_user_id'=>$senderInfo['app_user_id'],
                            'to_app_user_id'=>$receiverInfo['app_user_id'],
                            'user_id'=>$senderInfo['id'],
                            'content'=>$msg['msg'],
                            'nickname'=>$senderInfo['nickname'],
                            'head'=>$senderInfo['head'],
                            'type'=>$msg['type'],
                            'extra'=>json_decode($msg['extra'],true)
                        );
                        $messageArr = array(
                            'code'=>ReponseCodeService::CODE_OK,
                            'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_OK],
                            'data'=>json_encode($data,JSON_FORCE_OBJECT),
                            'action'=>'chat',
                            'nonce'=>$msg['nonce'],
                            'time'=>HelpService::strDateToMsectime($msg['created_at']),
                            'user_id'=>$userInfo['id'],
                            'msg_id'=>$msg['id'],
                        );
                        $friend['message_list'][] =  $messageArr;
                    }

                    $friends[] = $friend;
                }

            }

            #全部群
            $groupCondition['user_groups.user_id'] = $userInfo['id'];
            $groupCondition['user_groups.status'] = UserGroupModel::STATUS_NORMAL;

            $groupList = UserGroupModel::create()
                ->join('group_lists','group_lists.id=user_groups.group_id')
                ->field('group_lists.group_name,group_lists.cover,group_lists.id,user_groups.created_at')
                ->all( $groupCondition);

            #上次登录时间
            $redisPool = \EasySwoole\RedisPool\Redis::getInstance()->get('redis');
            $redis = $redisPool->getObj();
            $offlineTime = $redis->hGet(Config::getInstance()->getConf('CHAT.user_offline_time'),$userInfo['id']);
            $redisPool->recycleObj($redis);

            #计算全部群未读消息
            $groups = array();
            $serviceGroup = null;
            if(!empty($groupList)){
                $time =  HelpService::msectimeToStr($offlineTime);
                foreach ($groupList as $v){
                    $timezone = $time;
                    if( strtotime($time) < strtotime($v['created_at'])){
                        $timezone = $v['created_at'];
                    }

                    $count = MsgModel::create()
                        ->where(
                            [
                                'to_id'=>$v['id'],
                                'created_at'=>[ $timezone,'>'],
                                'sub_type'=>MsgModel::SUB_TYPE_GOUP_MSG
                            ]
                        )->count('id');

                    if($count<=0){
                        continue;
                    }

                   # $lastGroupMsg =  MsgModel::create()->order('id')->get(['to_id'=>$v['id'],'sub_type'=>MsgModel::SUB_TYPE_GOUP_MSG]);
                    $where = ['msgs.to_id'=>$v['id'],'msgs.sub_type'=>MsgModel::SUB_TYPE_GOUP_MSG];
                   $list = MsgModel::create()
                       ->join('users','users.id=msgs.user_id','left')
                       ->field('users.nickname,users.head,users.app_user_id,msgs.*')
                       ->order('msgs.id','desc')
                       ->limit(10)
                       ->all($where);
                    $messageList = array();
                   foreach ($list as $msg){
                       $data = array(
                           'group_id' =>$v['id'],
                           'content'=>$msg['msg'],
                           'type'=>$msg['type'],
                           'extra'=>json_encode($msg['extra']),
                           'app_user_id'=>$msg['app_user_id'],
                           'nickname'=>$msg['nickname'],
                           'head'=>$msg['head'],
                       );

                       $messageArr = array(
                           'code'=>ReponseCodeService::CODE_OK,
                           'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_OK],
                           'data'=>json_encode($data),
                           'action'=>'groupChat',
                           'nonce'=>$param['nonce'],
                           'time'=>HelpService::strDateToMsectime($msg['created_at']),
                           'msg_id'=>$msg['id'] ,
                           'group_id' => $v['id'],
                       );
                       $messageList[] = $messageArr;
                   }

                    $group['count'] = $count;
                    $group['group_name'] = $v['group_name'];
                    $group['cover'] = $v['cover'];
                    $group['message_list'] =  $messageList;
                    $group['group_id'] = $v['id'];
                    if($v['service_user_id']!=0){
                        $serviceGroup = $group;
                    }else{
                        $groups[] = $group;
                    }

                }
            }
            #客服群消息
            $extra = array(
                'friendList'=>$friends,
                'groupList'=>$groups,
                'serviceGroup'=>$serviceGroup
            );

            $data = array(
                'extra'=>$extra,
                'content'=>'',
                'type'=>MsgModel::MSG_TYPE_BASE,
                'sub_type'=>MsgModel::MSG_SUB_TYPE_PERSONAL,
                'app_id'=>$userInfo['app_id'],
            );


            $messageArr = array(
                'code'=>ReponseCodeService::CODE_OK,
                'msg'=>ReponseCodeService::$phrases[ReponseCodeService::CODE_OK],
                'data'=>json_encode($data),
                'action'=>'systemMessage',
                'nonce'=>HelpService::msectime().HelpService::createNonce(6),
                'time'=>HelpService::msectime(),
                'msg_id'=>null,
                'to_app_user_id'=>$userInfo['app_user_id'],
            );

            #推送客户端信息
            $pushmessageService = new PushMessageService();
            $pushmessageService->push($param['fd'],$messageArr,true);

            #添加消息同步任务
            $syncTable = TableManager::getInstance()->get(Config::getInstance()->getConf('CHAT.sync_message'));
            $syncTable->set($userInfo['id'],['fd'=>$param['fd'],'user_id'=>$userInfo['id']]);
            #登录状态设置为正常
            $readyTable =  TableManager::getInstance()->get(Config::getInstance()->getConf('CHAT.user_ready'));
            $readyInfo['user_id'] = $userInfo['id'];
            $readyInfo['status'] = 1;
            $readyTable->set($userInfo['id'], $readyInfo);
            return true;
        }catch(\Throwable $t){
            echo $t->getMessage();
            return ReponseCodeService::CODE_SERVICE_UNAVAILABLE;
        }
    }

    /**
     * 跨机消息推送，接收方去更新消息状态，发送方不管，只要网页不报错，都认为成功
     */
    public function pushToOtherServer($server,$fd,$content){
        echo 'http://'.$server.'/WebSocket/push?'.http_build_query(['fd'=>$fd,'content'=>$content]).PHP_EOL;
        $client = new \EasySwoole\HttpClient\HttpClient('http://'.$server.'/WebSocket/push?'.http_build_query(['fd'=>$fd,'content'=>$content]));
        $response = $client->get();
        if( $response->getErrCode()){
            return false;
        }
        return true;
    }
}